package com.wyh.socket_demo.endpoint;



import com.wyh.socket_demo.entiy.FilePacket;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import org.springframework.scheduling.annotation.Scheduled;

import javax.xml.bind.DatatypeConverter;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.ByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.security.MessageDigest;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Created by jeremy on 16/6/11.
 */
public class FileServer extends WebSocketServer {

    private ConcurrentMap<WebSocket, Map<String, Object>> clients = new ConcurrentHashMap<WebSocket, Map<String, Object>>();

    private String filePath = "G://";

    public FileServer(int port) throws UnknownHostException {
        super(new InetSocketAddress( port ));
    }

    @Override
    public void onOpen(WebSocket webSocket, ClientHandshake clientHandshake) {
        System.out.println("建立连接");
        clients.put(webSocket, new HashMap<String, Object>());
        FilePacket p = FilePacket.constructNewFilePacket("");
        System.out.println(p.getType());
        webSocket.send(p.getBuffer().array());
    }

    @Override
    public void onClose(WebSocket webSocket, int i, String s, boolean b) {
        clients.remove(webSocket);
    }

    @Override
    public void onMessage(WebSocket webSocket, String s) {
        System.out.println(s);
    }

    @Override
    public void onMessage(WebSocket webSocket, ByteBuffer bytes) {
        FilePacket p = FilePacket.parseByteBuffer(bytes);
        int code;
        switch (p.getType()) {
            case FilePacket.P_ACK_NEW_FILE:
                code = (int)p.getBuffer().get();
                if(FilePacket.SUCCESS_CODE == code){
                    System.out.println("server accept file request");
                    int fileNameLen = p.getBuffer().getInt();
                    byte[] fileNameBytes = new byte[fileNameLen];
                    p.getBuffer().get(fileNameBytes);
                    String fileName = new String(fileNameBytes, StandardCharsets.UTF_8);
                    startSendFileData(webSocket,fileName);
                }
                break;
            case FilePacket.P_ACK_FILE_END:
                code = (int)p.getBuffer().get();
                if(FilePacket.SUCCESS_CODE == code){
                    System.out.println("server save file sucessfully");
                    webSocket.close();
                }
                break;
        }
    }

    @Override
    public void onError(WebSocket webSocket, Exception e) {

    }

    @Override
    public void onStart() {

    }

    private void startSendFileData(WebSocket webSocket,String fileName) {
        try {
            System.out.println(fileName);
            ByteChannel fileChannel = Files.newByteChannel(Paths.get(this.filePath, fileName), EnumSet.of(StandardOpenOption.READ));
            ByteBuffer buffer = ByteBuffer.allocate(1 + 4096);
            buffer.order(ByteOrder.BIG_ENDIAN);

            MessageDigest md = MessageDigest.getInstance("MD5");

            int bytesRead = -1;

            buffer.clear();//make buffer ready for write
            buffer.put((byte)FilePacket.P_FILE_DATA);

            while((bytesRead = fileChannel.read(buffer)) != -1){
                buffer.flip();  //make buffer ready for read
                buffer.mark();
                buffer.get(); //skip a byte
                md.update(buffer);
                buffer.reset();
                webSocket.send(buffer);
                buffer.clear(); //make buffer ready for write
                buffer.put((byte)FilePacket.P_FILE_DATA);
            }

            byte[] digest = md.digest();
            String digestInHex = DatatypeConverter.printHexBinary(digest).toUpperCase();
            System.out.println("send file finished, digest: " + digestInHex);
            FilePacket p = FilePacket.constructFileEndPacket(digestInHex);
            webSocket.send(p.getBuffer());
        } catch (Exception e) {
            webSocket.close();
        }
    }


}
